package cn.chen.数据结构.栈;

import org.junit.Test;

import java.util.Scanner;

/**
 * 通过栈来计算表达式的值（不包含小括号）。
 * */
public class Calculator {

    public static void main(String[] args){

        String str="25*9-8/5+21-2*5+1*9/3";
        ArrayStack numStack=new ArrayStack(10);
        ArrayStack operStack=new ArrayStack(10);
        int num1=0,num2=0,res=0,index=0;
        char top=' ';
        StringBuilder su=new StringBuilder();

        while(true){

            if(index==str.length()) { // 判断index与字符长度的关系，然后结束循环

                numStack.push(Integer.parseInt(su.toString())); // 这个时候已经循环结束了，但是字符缓冲区中还有数据没有存在数栈中
                break;
            }

            char c = str.substring(index, index + 1).charAt(0);// 从str中截取一个字符，并且转成char类型
            index++;

            try {
                Integer.parseInt(c + "");   // 用这个来判断该字符是数字还是字符
                su.append(c);
            }
            catch(Exception e){

                // 将符号之前存储的数字放在栈中
                numStack.push(Integer.parseInt(su.toString()));
                su.delete(0,su.length());   // 清空字符缓冲区，字符缓冲区的delete方法，从包含头不包含尾，index从0开始

                // 将符号进行操作
                // 判断符号栈是否为空
                if(operStack.isEmpty()){

                    operStack.push(c);  // 将符号添加进栈中
                }
                else {  // 符号栈不为空，比较符号栈中的栈顶符号与该符号的优先级

                    int cOper = priority(c);
                    /*
                    * 循环访问栈顶：
                    *   1、栈顶与c进行比较，栈顶的小，就把c 压入栈中
                    *   2、栈顶的比c大或者等于，就将栈顶弹出，进行计算
                    *   3、然后继续访问栈顶与c进行比较，依次类推循环
                    * */
                    while(true) {   // 循环弹出栈顶，
                        if(operStack.isEmpty()) {
                            operStack.push(c);  // 弹出栈顶到栈都为空了，所以就直接将c压入栈中
                            break;
                        }
                        int topOper = priority(operStack.getTop());
                        if (topOper < cOper) { // 栈顶符号的优先级比该优先级小，所以就直接将该符号添加到栈顶中

                            operStack.push(c);
                            break;
                        } else {   // 栈顶符号优先级比该符号优先级高，弹出栈顶，并进行计算

                            top = (char) operStack.pop();
                            num1 = numStack.pop();
                            num2 = numStack.pop();

                            // 计算值，然后添加到数栈中
                            res = cal(num1, num2, top);
                            numStack.push(res);
                        }
                    }
                }
            }
        }
        while(!operStack.isEmpty()) {

            top = (char) operStack.pop();
            num1 = numStack.pop();
            num2 = numStack.pop();

            // 计算值，然后添加到数栈中
            res = cal(num1, num2, top);
            numStack.push(res);
        }
        System.out.println(str + "=" + numStack.pop());
    }
    // 判断运算符的优先级，程序员来定义的程序的优先级,数字越大，优先级越高
    public static int priority(int oper){

        if(oper=='+'|| oper == '-')
            return 0;
        if(oper == '*' || oper == '/')
            return 1;
        return -1;  // 这种就是其他符号就返回-1；
    }
    // 判断是不是一个运算符
    public static boolean isOper(char oper){

        return oper == '+' || oper == '-' || oper == '*' || oper == '/';
    }
    // 计算结果
    public static int cal(int num1,int num2,int oper){

        int cal=0;
        switch (oper){

            case '+':
                cal=num1+num2;
                break;
            case '-':
                cal=num2-num1;  // 这里是num2-num1，因为num2是后出栈的，但是在表达式中是前面的
                break;
            case '*':
                cal=num1*num2;
                break;
            case '/':
                cal=num2/num1;
                break;
        }
        return cal;
    }
}
